PAGE 118,123
TITLE DISK ----- 11/15/85  FIXED DISK BIOS
.286C
.XLIST
INCLUDE DSEG.INC
INCLUDE POSTEQU.INC
.LIST
CODE	SEGMENT BYTE PUBLIC

	PUBLIC	DISK_IO
	PUBLIC	DISK_SETUP
	PUBLIC	HD_INT

	EXTRN	CMOS_READ:NEAR
	EXTRN	CMOS_WRITE:NEAR
	EXTRN	DDS:NEAR
	EXTRN	E_MSG:NEAR
	EXTRN	F1780:NEAR
	EXTRN	F1781:NEAR
	EXTRN	F1782:NEAR
	EXTRN	F1790:NEAR
	EXTRN	F1791:NEAR
	EXTRN	FD_TBL:NEAR

;--- INT 13H -------------------------------------------------------------------
;									       :
; FIXED DISK I/O INTERFACE						       :
;									       :
;	THIS INTERFACE PROVIDES ACCESS TO 5 1/4" FIXED DISKS THROUGH           :
;	THE IBM FIXED DISK CONTROLLER.					       :
;									       :
;	THE  BIOS  ROUTINES  ARE  MEANT  TO  BE  ACCESSED  THROUGH	       :
;	SOFTWARE  INTERRUPTS  ONLY.    ANY  ADDRESSES  PRESENT	IN	       :
;	THESE  LISTINGS  ARE  INCLUDED	 ONLY	FOR  COMPLETENESS,	       :
;	NOT  FOR  REFERENCE.  APPLICATIONS   WHICH  REFERENCE  ANY	       :
;	ABSOLUTE  ADDRESSES  WITHIN  THE  CODE	SEGMENTS  OF  BIOS	       :
;	VIOLATE  THE  STRUCTURE  AND  DESIGN  OF  BIOS. 		       :
;									       :
;------------------------------------------------------------------------------:
;									       :
; INPUT  (AH)= HEX COMMAND VALUE					       :
;									       :
;	(AH)= 00H  RESET DISK (DL = 80H,81H) / DISKETTE 		       :
;	(AH)= 01H  READ THE STATUS OF THE LAST DISK OPERATION INTO (AL)        :
;		    NOTE: DL < 80H - DISKETTE				       :
;			  DL > 80H - DISK				       :
;	(AH)= 02H  READ THE DESIRED SECTORS INTO MEMORY 		       :
;	(AH)= 03H  WRITE THE DESIRED SECTORS FROM MEMORY		       :
;	(AH)= 04H  VERIFY THE DESIRED SECTORS				       :
;	(AH)= 05H  FORMAT THE DESIRED TRACK				       :
;	(AH)= 06H  UNUSED						       :
;	(AH)= 07H  UNUSED						       :
;	(AH)= 08H  RETURN THE CURRENT DRIVE PARAMETERS			       :
;	(AH)= 09H  INITIALIZE DRIVE PAIR CHARACTERISTICS		       :
;		    INTERRUPT 41 POINTS TO DATA BLOCK FOR DRIVE 0	       :
;		    INTERRUPT 46 POINTS TO DATA BLOCK FOR DRIVE 1	       :
;	(AH)= 0AH  READ LONG						       :
;	(AH)= 0BH  WRITE LONG  (READ & WRITE LONG ENCOMPASS 512 + 4 BYTES ECC) :
;	(AH)= 0CH  SEEK 						       :
;	(AH)= 0DH  ALTERNATE DISK RESET (SEE DL)			       :
;	(AH)= 0EH  UNUSED						       :
;	(AH)= 0FH  UNUSED						       :
;	(AH)= 10H  TEST DRIVE READY					       :
;	(AH)= 11H  RECALIBRATE						       :
;	(AH)= 12H  UNUSED						       :
;	(AH)= 13H  UNUSED						       :
;	(AH)= 14H  CONTROLLER INTERNAL DIAGNOSTIC			       :
;	(AH)= 15H  READ DASD TYPE					       :
;									       :
;-------------------------------------------------------------------------------
;									       :
;	REGISTERS USED FOR FIXED DISK OPERATIONS			       :
;									       :
;		(DL)	-  DRIVE NUMBER     (80H-81H FOR DISK. VALUE CHECKED)  :
;		(DH)	-  HEAD NUMBER	    (0-15 ALLOWED, NOT VALUE CHECKED)  :
;		(CH)	-  CYLINDER NUMBER  (0-1023, NOT VALUE CHECKED)(SEE CL):
;		(CL)	-  SECTOR NUMBER    (1-17, NOT VALUE CHECKED)	       :
;									       :
;			   NOTE: HIGH 2 BITS OF CYLINDER NUMBER ARE PLACED     :
;				 IN THE HIGH 2 BITS OF THE CL REGISTER	       :
;				 (10 BITS TOTAL)			       :
;									       :
;		(AL)	-  NUMBER OF SECTORS (MAXIMUM POSSIBLE RANGE 1-80H,    :
;					      FOR READ/WRITE LONG 1-79H)       :
;									       :
;		(ES:BX) -  ADDRESS OF BUFFER FOR READS AND WRITES,	       :
;			   (NOT REQUIRED FOR VERIFY)			       :
;									       :
;		FORMAT (AH=5) ES:BX POINTS TO A 512 BYTE BUFFER. THE FIRST     :
;			   2*(SECTORS/TRACK) BYTES CONTAIN F,N FOR EACH SECTOR.:
;			   F = 00H FOR A GOOD SECTOR			       :
;			       80H FOR A BAD SECTOR			       :
;			   N = SECTOR NUMBER				       :
;			   FOR AN INTERLEAVE OF 2 AND 17 SECTORS/TRACK	       :
;			   THE TABLE SHOULD BE: 			       :
;									       :
;		   DB	   00H,01H,00H,0AH,00H,02H,00H,0BH,00H,03H,00H,0CH     :
;		   DB	   00H,04H,00H,0DH,00H,05H,00H,0EH,00H,06H,00H,0FH     :
;		   DB	   00H,07H,00H,10H,00H,08H,00H,11H,00H,09H	       :
;									       :
;-------------------------------------------------------------------------------
PAGE
;-------------------------------------------------------------------------------
; OUTPUT								       :
;	AH = STATUS OF CURRENT OPERATION				       :
;	     STATUS BITS ARE DEFINED IN THE EQUATES BELOW		       :
;	CY = 0	SUCCESSFUL OPERATION (AH=0 ON RETURN)			       :
;	CY = 1	FAILED OPERATION (AH HAS ERROR REASON)			       :
;									       :
;	NOTE:	ERROR 11H  INDICATES THAT THE DATA READ HAD A RECOVERABLE      :
;		ERROR WHICH WAS CORRECTED BY THE ECC ALGORITHM.  THE DATA      :
;		IS PROBABLY GOOD,   HOWEVER THE BIOS ROUTINE INDICATES AN      :
;		ERROR TO ALLOW THE CONTROLLING PROGRAM A CHANCE TO DECIDE      :
;		FOR ITSELF.  THE  ERROR  MAY  NOT  RECUR  IF  THE DATA IS      :
;		REWRITTEN.						       :
;									       :
;	IF DRIVE PARAMETERS WERE REQUESTED (DL >= 80H), 		       :
;	   INPUT:							       :
;	     (DL) = DRIVE NUMBER					       :
;	   OUTPUT:							       :
;	     (DL) = NUMBER OF CONSECUTIVE ACKNOWLEDGING DRIVES ATTACHED (1-2)  :
;		    (CONTROLLER CARD ZERO TALLY ONLY)			       :
;	     (DH) = MAXIMUM USEABLE VALUE FOR HEAD NUMBER		       :
;	     (CH) = MAXIMUM USEABLE VALUE FOR CYLINDER NUMBER		       :
;	     (CL) = MAXIMUM USEABLE VALUE FOR SECTOR NUMBER		       :
;		    AND CYLINDER NUMBER HIGH BITS			       :
;									       :
;	IF READ DASD TYPE WAS REQUESTED,				       :
;									       :
;	AH = 0 - NOT PRESENT						       :
;	     1 - DISKETTE - NO CHANGE LINE AVAILABLE			       :
;	     2 - DISKETTE - CHANGE LINE AVAILABLE			       :
;	     3 - FIXED DISK						       :
;									       :
;	CX,DX = NUMBER OF 512 BYTE BLOCKS WHEN AH = 3			       :
;									       :
;	REGISTERS WILL BE PRESERVED EXCEPT WHEN THEY ARE USED TO RETURN        :
;	INFORMATION.							       :
;									       :
;	NOTE: IF AN ERROR IS REPORTED BY THE DISK CODE, THE APPROPRIATE        :
;		ACTION IS TO RESET THE DISK, THEN RETRY THE OPERATION.	       :
;									       :
;-------------------------------------------------------------------------------

SENSE_FAIL	EQU	0FFH		; NOT IMPLEMENTED
NO_ERR		EQU	0E0H		; STATUS ERROR/ERROR REGISTER=0
WRITE_FAULT	EQU	0CCH		; WRITE FAULT ON SELECTED DRIVE
UNDEF_ERR	EQU	0BBH		; UNDEFINED ERROR OCCURRED
NOT_RDY 	EQU	0AAH		; DRIVE NOT READY
TIME_OUT	EQU	80H		; ATTACHMENT FAILED TO RESPOND
BAD_SEEK	EQU	40H		; SEEK OPERATION FAILED
BAD_CNTLR	EQU	20H		; CONTROLLER HAS FAILED
DATA_CORRECTED	EQU	11H		; ECC CORRECTED DATA ERROR
BAD_ECC 	EQU	10H		; BAD ECC ON DISK READ
BAD_TRACK	EQU	0BH		; NOT IMPLEMENTED
BAD_SECTOR	EQU	0AH		; BAD SECTOR FLAG DETECTED
DMA_BOUNDARY	EQU	09H		; DATA EXTENDS TOO FAR
INIT_FAIL	EQU	07H		; DRIVE PARAMETER ACTIVITY FAILED
BAD_RESET	EQU	05H		; RESET FAILED
RECORD_NOT_FND	EQU	04H		; REQUESTED SECTOR NOT FOUND
BAD_ADDR_MARK	EQU	02H		; ADDRESS MARK NOT FOUND
BAD_CMD 	EQU	01H		; BAD COMMAND PASSED TO DISK I/O


;--------------------------------------------------------
;							:
; FIXED DISK PARAMETER TABLE				:
;  -  THE TABLE IS COMPOSED OF A BLOCK DEFINED AS:	:
;							:
;  +0	(1 WORD) - MAXIMUM NUMBER OF CYLINDERS		:
;  +2	(1 BYTE) - MAXIMUM NUMBER OF HEADS		:
;  +3	(1 WORD) - NOT USED/SEE PC-XT			:
;  +5	(1 WORD) - STARTING WRITE PRECOMPENSATION CYL	:
;  +7	(1 BYTE) - MAXIMUM ECC DATA BURST LENGTH	:
;  +8	(1 BYTE) - CONTROL BYTE 			:
;		   BIT	  7 DISABLE RETRIES -OR-	:
;		   BIT	  6 DISABLE RETRIES		:
;		   BIT	  3 MORE THAN 8 HEADS		:
;  +9	(3 BYTES)- NOT USED/SEE PC-XT			:
; +12	(1 WORD) - LANDING ZONE 			:
; +14	(1 BYTE) - NUMBER OF SECTORS/TRACK		:
; +15	(1 BYTE) - RESERVED FOR FUTURE USE		:
;							:
;	 - TO DYNAMICALLY DEFINE A SET OF PARAMETERS	:
;	   BUILD A TABLE FOR UP TO 15 TYPES AND PLACE	:
;	   THE CORRESPONDING VECTOR INTO INTERRUPT 41	:
;	   FOR DRIVE 0 AND INTERRUPT 46 FOR DRIVE 1.	:
;							:
;--------------------------------------------------------
PAGE
;--------------------------------------------------------
;							:
; HARDWARE SPECIFIC VALUES				:
;							:
;  -  CONTROLLER I/O PORT				:
;							:
;     > WHEN READ FROM: 				:
;	HF_PORT+0 - READ DATA (FROM CONTROLLER TO CPU)	:
;	HF_PORT+1 - GET ERROR REGISTER			:
;	HF_PORT+2 - GET SECTOR COUNT			:
;	HF_PORT+3 - GET SECTOR NUMBER			:
;	HF_PORT+4 - GET CYLINDER LOW			:
;	HF_PORT+5 - GET CYLINDER HIGH (2 BITS)		:
;	HF_PORT+6 - GET SIZE/DRIVE/HEAD 		:
;	HF_PORT+7 - GET STATUS REGISTER 		:
;							:
;     > WHEN WRITTEN TO:				:
;	HF_PORT+0 - WRITE DATA (FROM CPU TO CONTROLLER) :
;	HF_PORT+1 - SET PRECOMPENSATION CYLINDER	:
;	HF_PORT+2 - SET SECTOR COUNT			:
;	HF_PORT+3 - SET SECTOR NUMBER			:
;	HF_PORT+4 - SET CYLINDER LOW			:
;	HF_PORT+5 - SET CYLINDER HIGH (2 BITS)		:
;	HF_PORT+6 - SET SIZE/DRIVE/HEAD 		:
;	HF_PORT+7 - SET COMMAND REGISTER		:
;							:
;--------------------------------------------------------

HF_PORT 	EQU	01F0H		; DISK PORT
HF_REG_PORT	EQU	03F6H

;-----		STATUS REGISTER

ST_ERROR	EQU	00000001B	;
ST_INDEX	EQU	00000010B	;
ST_CORRCTD	EQU	00000100B	; ECC CORRECTION SUCCESSFUL
ST_DRQ		EQU	00001000B	;
ST_SEEK_COMPL	EQU	00010000B	; SEEK COMPLETE
ST_WRT_FLT	EQU	00100000B	; WRITE FAULT
ST_READY	EQU	01000000B	;
ST_BUSY 	EQU	10000000B	;

;-----		ERROR REGISTER

ERR_DAM 	EQU	00000001B	; DATA ADDRESS MARK NOT FOUND
ERR_TRK_0	EQU	00000010B	; TRACK 0 NOT FOUND ON RECAL
ERR_ABORT	EQU	00000100B	; ABORTED COMMAND
;		EQU	00001000B	; NOT USED
ERR_ID		EQU	00010000B	; ID NOT FOUND
;		EQU	00100000B	; NOT USED
ERR_DATA_ECC	EQU	01000000B
ERR_BAD_BLOCK	EQU	10000000B


RECAL_CMD	EQU	00010000B	; DRIVE RECAL	(10H)
READ_CMD	EQU	00100000B	;	READ	(20H)
WRITE_CMD	EQU	00110000B	;	WRITE	(30H)
VERIFY_CMD	EQU	01000000B	;	VERIFY	(40H)
FMTTRK_CMD	EQU	01010000B	; FORMAT TRACK	(50H)
INIT_CMD	EQU	01100000B	;   INITIALIZE	(60H)
SEEK_CMD	EQU	01110000B	;	SEEK	(70H)
DIAG_CMD	EQU	10010000B	; DIAGNOSTIC	(90H)
SET_PARM_CMD	EQU	10010001B	; DRIVE PARMS	(91H)
NO_RETRIES	EQU	00000001B	; CHD MODIFIER	(01H)
ECC_MODE	EQU	00000010B	; CMD MODIFIER	(02H)
BUFFER_MODE	EQU	00001000B	; CMD MODIFIER	(08H)

MAX_FILE	EQU	2
S_MAX_FILE	EQU	2

DELAY_1 	EQU	25H		; DELAY FOR OPERATION COMPLETE
DELAY_2 	EQU	0600H		; DELAY FOR READY
DELAY_3 	EQU	0100H		; DELAY FOR DATA REQUEST

HF_FAIL 	EQU	08H		; CMOS FLAG IN BYTE 0EH

;-----		COMMAND BLOCK REFERENCE

@CMD_BLOCK	EQU	BYTE PTR [BP]-8 ; @CMD_BLOCK REFERENCES BLOCK HEAD IN SS
					;  (BP) POINTS TO COMMAND BLOCK TAIL
					;	AS DEFINED BY THE "ENTER" PARMS
PAGE
;----------------------------------------------------------------
; FIXED DISK I/O SETUP						:
;								:
;  -  ESTABLISH TRANSFER VECTORS FOR THE FIXED DISK		:
;  -  PERFORM POWER ON DIAGNOSTICS				:
;     SHOULD AN ERROR OCCUR A "1701" MESSAGE IS DISPLAYED       :
;								:
;----------------------------------------------------------------
	ASSUME	CS:CODE,DS:ABS0 			; WORK OFF DS REGISTER

DISK_SETUP	PROC	NEAR
	CLI
	MOV	AX,ABS0 				; GET ABSOLUTE SEGMENT
	MOV	DS,AX					; SET SEGMENT REGISTER
	MOV	AX,WORD PTR @ORG_VECTOR 		; GET DISKETTE VECTOR
	MOV	WORD PTR @DISK_VECTOR,AX		;  INTO INT 40H
	MOV	AX,WORD PTR @ORG_VECTOR+2
	MOV	WORD PTR @DISK_VECTOR+2,AX
	MOV	WORD PTR @ORG_VECTOR,OFFSET DISK_IO	; FIXED DISK HANDLER
	MOV	WORD PTR @ORG_VECTOR+2,CS
	MOV	WORD PTR @HDISK_INT,OFFSET HD_INT	; FIXED DISK INTERRUPT
	MOV	WORD PTR @HDISK_INT+2,CS
	MOV	WORD PTR @HF_TBL_VEC,OFFSET FD_TBL	; PARM TABLE DRIVE 80
	MOV	WORD PTR @HF_TBL_VEC+2,CS
	MOV	WORD PTR @HF1_TBL_VEC,OFFSET FD_TBL	; PARM TABLE DRIVE 81
	MOV	WORD PTR @HF1_TBL_VEC+2,CS
	IN	AL,INTB01			; TURN ON SECOND INTERRUPT CHIP
	AND	AL,0BFH
	JMP	$+2
	OUT	INTB01,AL
	IN	AL,INTA01		; LET INTERRUPTS PASS THRU TO
	AND	AL,0FBH 		;  SECOND CHIP
	JMP	$+2
	OUT	INTA01,AL

	STI
	ASSUME	DS:DATA,ES:ABS0
	PUSH	DS			; MOVE ABS0 POINTER TO
	POP	ES			; EXTRA SEGMENT POINTER
	CALL	DDS			; ESTABLISH DATA SEGMENT
	MOV	@DISK_STATUS1,0 	; RESET THE STATUS INDICATOR
	MOV	@HF_NUM,0		; ZERO NUMBER OF FIXED DISKS
	MOV	@CONTROL_BYTE,0
	MOV	AL,CMOS_DIAG+NMI
	CALL	CMOS_READ		; CHECK CMOS VALIDITY
	MOV	AH,AL			; SAVE CMOS FLAG
	AND	AL,BAD_BAT+BAD_CKSUM	; CHECK FOR VALID CMOS
	JZ	L1
	JMP	POD_DONE		; CMOS NOT VALID -- NO FIXED DISK
L1:
	AND	AH,NOT HF_FAIL		; ALLOW FIXED DISK IPL
	MOV	AL,CMOS_DIAG+NMI	; WRITE IT BACK
	CALL	CMOS_WRITE
	MOV	AL,CMOS_DISK+NMI
	CALL	CMOS_READ
	MOV	@PORT_OFF,0		; ZERO CARD OFFSET
	MOV	BL,AL			; SAVE FIXED DISK BYTE
	AND	AX,00F0H		; GET FIRST DRIVE TYPE AS OFFSET
	JZ	POD_DONE		; NO FIXED DISKS

	CMP	AL,0F0H 		; CHECK FOR EXTENDED DRIVE TYPE BYTE USE
	JNE	L2			; USE DRIVE TYPE 1 --> 14 IF NOT IN USE

	MOV	AL,CMOS_DISK_1+NMI	; GET EXTENDED TYPE FOR DRIVE C:
	CALL	CMOS_READ		; FROM CMOS
	CMP	AL,0			; IS TYPE SET TO ZERO
	JE	POD_DONE		; EXIT IF NOT VALID AND NO FIXED DISKS
	CMP	AL,47			; IS TYPE WITHIN VALID RANGE
	JA	POD_DONE		; EXIT WITH NO FIXED DISKS IF NOT VALID
	SHL	AX,4			; ADJUST TYPE TO HIGH NIBBLE
L2:
	ADD	AX,OFFSET FD_TBL-16D	; COMPUTE OFFSET OF FIRST DRIVE TABLE
	MOV	WORD PTR @HF_TBL_VEC,AX ; SAVE IN VECTOR POINTER
	MOV	@HF_NUM,1		; AT LEAST ONE DRIVE
	MOV	AL,BL
	SHL	AL,4			; GET SECOND DRIVE TYPE
	JZ	SHORT L4		; ONLY ONE DRIVE
	MOV	AH,0

	CMP	AL,0F0H 		; CHECK FOR EXTENDED DRIVE TYPE BYTE USE
	JNE	L3			; USE DRIVE TYPE 1 --> 14 IF NOT IN USE

	MOV	AL,CMOS_DISK_2+NMI	; GET EXTENDED TYPE FOR DRIVE C:
	CALL	CMOS_READ		; FROM CMOS
	CMP	AL,0			; IS TYPE SET TO ZERO
	JE	L4			; SKIP IF SECOND FIXED DISK NOT VALID
	CMP	AL,47			; IS TYPE WITHIN VALID RANGE
	JA	L4			; SKIP IF NOT VALID
	SHL	AX,4			; ADJUST TYPE TO HIGH NIBBLE
L3:
	ADD	AX,OFFSET FD_TBL-16D	; COMPUTE OFFSET FOR SECOND FIXED DISK
	MOV	BX,AX
	CMP	WORD PTR CS:[BX],0	; CHECK FOR ZERO CYLINDERS IN TABLE
	JE	L4			; SKIP DRIVE IF NOT A VALID TABLE ENTRY
	MOV	WORD PTR @HF1_TBL_VEC,AX
	MOV	@HF_NUM,2		; TWO DRIVES
L4:
	MOV	DL,80H			; CHECK THE CONTROLLER
	MOV	AH,14H			; USE CONTROLLER DIAGNOSTIC COMMAND
	INT	13H			; CALL BIOS WITH DIAGNOSTIC COMMAND
	JC	CTL_ERRX		; DISPLAY ERROR MESSAGE IF BAD RETURN
	MOV	AX,@TIMER_LOW		; GET START TIMER COUNTS
	MOV	BX,AX
	ADD	AX,6*182		; 60 SECONDS* 18.2
	MOV	CX,AX
	CALL	HD_RESET_1		; SET UP DRIVE 0
	CMP	@HF_NUM,1		; WERE THERE TWO DRIVES?
	JBE	POD_DONE		; NO-ALL DONE
	MOV	DL,81H			; SET UP DRIVE 1
	CALL	HD_RESET_1
POD_DONE:
	RET

;-----	POD_ERROR

CTL_ERRX:
	MOV	SI,OFFSET F1782 	; CONTROLLER ERROR
	CALL	SET_FAIL		; DO NOT IPL FROM DISK
	CALL	E_MSG			; DISPLAY ERROR AND SET (BP) ERROR FLAG
	JMP	POD_DONE


HD_RESET_1	PROC	NEAR
	PUSH	BX			; SAVE TIMER LIMITS
	PUSH	CX
RES_1:	MOV	AH,09H			; SET DRIVE PARAMETERS
	INT	13H
	JC	RES_2
	MOV	AH,11H			; RECALIBRATE DRIVE
	INT	13H
	JNC	RES_CK			; DRIVE OK
RES_2:	CALL	POD_TCHK		; CHECK TIME OUT
	JNC	RES_1
RES_FL: MOV	SI,OFFSET F1781 	; INDICATE DISK 1 FAILURE
	TEST	DL,1
	JNZ	RES_E1
	MOV	SI,OFFSET F1780 	; INDICATE DISK 0 FAILURE
	CALL	SET_FAIL		; DO NOT TRY TO IPL DISK 0
	JMP	SHORT RES_E1
RES_RS: MOV	AH,00H			; RESET THE DRIVE
	INT	13H
RES_CK: MOV	AH,08H			; GET MAX CYLINDER,HEAD,SECTOR
	MOV	BL,DL			; SAVE DRIVE CODE
	INT	13H
	JC	RES_ER
	MOV	WORD PTR @NEC_STATUS,CX ; SAVE MAX CYLINDER, SECTOR
	MOV	DL,BL			; RESTORE DRIVE CODE
RES_3:	MOV	AX,0401H		; VERIFY THE LAST SECTOR
	INT	13H
	JNC	RES_OK			; VERIFY OK
	CMP	AH,BAD_SECTOR		; OK ALSO IF JUST ID READ
	JE	RES_OK
	CMP	AH,DATA_CORRECTED
	JE	RES_OK
	CMP	AH,BAD_ECC
	JE	RES_OK
	CALL	POD_TCHK		; CHECK FOR TIME OUT
	JC	RES_ER			; FAILED
	MOV	CX,WORD PTR @NEC_STATUS ; GET SECTOR ADDRESS, AND CYLINDER
	MOV	AL,CL			; SEPARATE OUT SECTOR NUMBER
	AND	AL,3FH
	DEC	AL			; TRY PREVIOUS ONE
	JZ	RES_RS			; WE'VE TRIED ALL SECTORS ON TRACK
	AND	CL,0C0H 		; KEEP CYLINDER BITS
	OR	CL,AL			; MERGE SECTOR WITH CYLINDER BITS
	MOV	WORD PTR @NEC_STATUS,CX ; SAVE CYLINDER, NEW SECTOR NUMBER
	JMP	RES_3			; TRY AGAIN
RES_ER: MOV	SI,OFFSET F1791 	; INDICATE DISK 1 ERROR
	TEST	DL,1
	JNZ	RES_E1
	MOV	SI,OFFSET F1790 	; INDICATE DISK 0 ERROR
RES_E1:
	CALL	E_MSG			; DISPLAY ERROR AND SET (BP) ERROR FLAG
RES_OK:
	POP	CX			; RESTORE TIMER LIMITS
	POP	BX
	RET
HD_RESET_1	ENDP

SET_FAIL	PROC	NEAR
	MOV	AX,X*(CMOS_DIAG+NMI)	; GET CMOS ERROR BYTE
	CALL	CMOS_READ
	OR	AL,HF_FAIL		; SET DO NOT IPL FROM DISK FLAG
	XCHG	AH,AL			; SAVE IT
	CALL	CMOS_WRITE		; PUT IT OUT
	RET
SET_FAIL	ENDP

POD_TCHK	PROC	NEAR		; CHECK FOR 30 SECOND TIME OUT
	POP	AX			; SAVE RETURN
	POP	CX			; GET TIME OUT LIMITS
	POP	BX
	PUSH	BX			; AND SAVE THEM AGAIN
	PUSH	CX
	PUSH	AX			; RESTORE RETURN
	MOV	AX,@TIMER_LOW		; AX = CURRENT TIME
					; BX = START TIME
					; CX = END TIME
	CMP	BX,CX
	JB	TCHK1			; START < END
	CMP	BX,AX
	JB	TCHKG			; END < START < CURRENT
	JMP	SHORT TCHK2		; END, CURRENT < START
TCHK1:	CMP	AX,BX
	JB	TCHKNG			; CURRENT < START < END
TCHK2:	CMP	AX,CX
	JB	TCHKG			; START < CURRENT < END
					; OR CURRENT < END < START
TCHKNG: STC				; CARRY SET INDICATES TIME OUT
	RET
TCHKG:	CLC				; INDICATE STILL TIME
	RET
POD_TCHK	ENDP

DISK_SETUP	ENDP
PAGE
;----------------------------------------
;	FIXED DISK BIOS ENTRY POINT	:
;----------------------------------------

DISK_IO PROC	FAR
	ASSUME	DS:DATA,ES:NOTHING
	CMP	DL,80H			; TEST FOR FIXED DISK DRIVE
	JAE	A1			; YES, HANDLE HERE
	INT	40H			; DISKETTE HANDLER
RET_2:
	RET	2			; BACK TO CALLER

A1:
	STI				; ENABLE INTERRUPTS
	OR	AH,AH
	JNZ	A2
	INT	40H			; RESET NEC WHEN AH=0
	SUB	AH,AH
	CMP	DL,(80H + S_MAX_FILE - 1)
	JA	RET_2
A2:
	CMP	AH,08H			; GET PARAMETERS IS A SPECIAL CASE
	JNZ	A3
	JMP	GET_PARM_N
A3:	CMP	AH,15H			; READ DASD TYPE IS ALSO
	JNZ	A4
	JMP	READ_DASD_TYPE

A4:					;	SAVE REGISTERS DURING OPERATION
	ENTER	8,0			; SAVE (BP) AND MAKE ROOM FOR @CMD_BLOCK
	PUSH	BX			;  IN THE STACK, THE COMMAND BLOCK IS:
	PUSH	CX			;   @CMD_BLOCK == BYTE PTR [BP]-8
	PUSH	DX
	PUSH	DS
	PUSH	ES
	PUSH	SI
	PUSH	DI
	OR	AH,AH			; CHECK FOR RESET
	JNZ	A5
	MOV	DL,80H			; FORCE DRIVE 80 FOR RESET
A5:	CALL	DISK_IO_CONT		; PERFORM THE OPERATION
	CALL	DDS			; ESTABLISH SEGMENT
	MOV	AH,@DISK_STATUS1	; GET STATUS FROM OPERATION
	CMP	AH,1			; SET THE CARRY FLAG TO INDICATE
	CMC				; SUCCESS OR FAILURE
	POP	DI			; RESTORE REGISTERS
	POP	SI
	POP	ES
	POP	DS
	POP	DX
	POP	CX
	POP	BX
	LEAVE				; ADJUST (SP) AND RESTORE (BP)
	RET	2			; THROW AWAY SAVED FLAGS
DISK_IO ENDP

M1	LABEL	WORD			; FUNCTION TRANSFER TABLE
	DW	DISK_RESET		; 000H
	DW	RETURN_STATUS		; 001H
	DW	DISK_READ		; 002H
	DW	DISK_WRITE		; 003H
	DW	DISK_VERF		; 004H
	DW	FMT_TRK 		; 005H
	DW	BAD_COMMAND		; 006H	FORMAT BAD SECTORS
	DW	BAD_COMMAND		; 007H	FORMAT DRIVE
	DW	BAD_COMMAND		; 008H	RETURN PARAMETERS
	DW	INIT_DRV		; 009H
	DW	RD_LONG 		; 00AH
	DW	WR_LONG 		; 00BH
	DW	DISK_SEEK		; 00CH
	DW	DISK_RESET		; 00DH
	DW	BAD_COMMAND		; 00EH	READ BUFFER
	DW	BAD_COMMAND		; 00FH	WRITE BUFFER
	DW	TST_RDY 		; 010H
	DW	HDISK_RECAL		; 011H
	DW	BAD_COMMAND		; 012H	MEMORY DIAGNOSTIC
	DW	BAD_COMMAND		; 013H	DRIVE DIAGNOSTIC
	DW	CTLR_DIAGNOSTIC 	; 014H	CONTROLLER DIAGNOSTIC
M1L	EQU	$-M1

DISK_IO_CONT	PROC	NEAR
	CALL	DDS			; ESTABLISH SEGMENT
	CMP	AH,01H			; RETURN STATUS
	JNZ	SU0
	JMP	RETURN_STATUS
SU0:
	MOV	@DISK_STATUS1,0 	; RESET THE STATUS INDICATOR
	PUSH	BX			; SAVE DATA ADDRESS
	MOV	BL,@HF_NUM		; GET NUMBER OF DRIVES
	PUSH	AX
	AND	DL,7FH			; GET DRIVE AS 0 OR 1
	CMP	BL,DL
	JBE	BAD_COMMAND_POP 	; INVALID DRIVE
	PUSH	ES
	CALL	GET_VEC 		; GET DISK PARAMETERS
	MOV	AX,WORD PTR ES:[BX][5]	; GET WRITE PRE-COMPENSATION CYLINDER
	SHR	AX,2
	MOV	@CMD_BLOCK,AL
	MOV	AL,BYTE PTR ES:[BX][8]	; GET CONTROL BYTE MODIFIER
	PUSH	DX
	MOV	DX,HF_REG_PORT
	OUT	DX,AL			; SET EXTRA HEAD OPTION
	POP	DX
	POP	ES
	MOV	AH,@CONTROL_BYTE	; SET EXTRA HEAD OPTION IN
	AND	AH,0C0H 		; CONTROL BYTE
	OR	AH,AL
	MOV	@CONTROL_BYTE,AH
	POP	AX
	MOV	@CMD_BLOCK+1,AL 	; SECTOR COUNT
	PUSH	AX
	MOV	AL,CL			; GET SECTOR NUMBER
	AND	AL,3FH
	MOV	@CMD_BLOCK+2,AL
	MOV	@CMD_BLOCK+3,CH 	; GET CYLINDER NUMBER
	MOV	AL,CL
	SHR	AL,6
	MOV	@CMD_BLOCK+4,AL 	; CYLINDER HIGH ORDER 2 BITS
	MOV	AL,DL			; DRIVE NUMBER
	SHL	AL,4
	AND	DH,0FH			; HEAD NUMBER
	OR	AL,DH
	OR	AL,80H OR 20H		; ECC AND 512 BYTE SECTORS
	MOV	@CMD_BLOCK+5,AL 	; ECC/SIZE/DRIVE/HEAD
	POP	AX
	PUSH	AX
	MOV	AL,AH			; GET INTO LOW BYTE
	XOR	AH,AH			; ZERO HIGH BYTE
	SAL	AX,1			; *2 FOR TABLE LOOKUP
	MOV	SI,AX			; PUT INTO SI FOR BRANCH
	CMP	AX,M1L			; TEST WITHIN RANGE
	JNB	BAD_COMMAND_POP
	POP	AX			; RESTORE AX
	POP	BX			; AND DATA ADDRESS
	PUSH	CX
	PUSH	AX			; ADJUST ES:BX
	MOV	CX,BX			; GET 3 HIGH ORDER NIBBLES OF BX
	SHR	CX,4
	MOV	AX,ES
	ADD	AX,CX
	MOV	ES,AX
	AND	BX,000FH		; ES:BX CHANGED TO ES:000X
	POP	AX
	POP	CX
	JMP	WORD PTR CS:[SI + OFFSET M1]
BAD_COMMAND_POP:
	POP	AX
	POP	BX
BAD_COMMAND:
	MOV	@DISK_STATUS1,BAD_CMD	; COMMAND ERROR
	MOV	AL,0
	RET
DISK_IO_CONT	ENDP

;----------------------------------------
;	RESET THE DISK SYSTEM  (AH=00H) :
;----------------------------------------

DISK_RESET	PROC	NEAR
	CLI
	IN	AL,INTB01		; GET THE MASK REGISTER
	JMP	$+2
	AND	AL,0BFH 		; ENABLE FIXED DISK INTERRUPT
	OUT	INTB01,AL
	STI				; START INTERRUPTS
	MOV	AL,04H
	MOV	DX,HF_REG_PORT
	OUT	DX,AL			; RESET
	MOV	CX,10			; DELAY COUNT
DRD:	DEC	CX
	JNZ	DRD			; WAIT 4.8 MICRO-SEC
	MOV	AL,@CONTROL_BYTE
	AND	AL,0FH			; SET HEAD OPTION
	OUT	DX,AL			; TURN RESET OFF
	CALL	NOT_BUSY
	JNZ	DRERR			; TIME OUT ON RESET
	MOV	DX,HF_PORT+1
	IN	AL,DX			; GET RESET STATUS
	CMP	AL,1
	JNZ	DRERR			; BAD RESET STATUS
	AND	@CMD_BLOCK+5,0EFH	; SET TO DRIVE 0
	SUB	DL,DL
	CALL	INIT_DRV		; SET MAX HEADS
	CALL	HDISK_RECAL		; RECAL TO RESET SEEK SPEED
	CMP	@HF_NUM,1		; CHECK FOR DRIVE
	JBE	DRE
	OR	@CMD_BLOCK+5,010H	; SET TO DRIVE
	MOV	DL,1
	CALL	INIT_DRV		; SET MAX HEADS
	CALL	HDISK_RECAL		; RECAL TO RESET SEEK SPEED
DRE:	MOV	@DISK_STATUS1,0 	; IGNORE ANY SET UP ERRORS
	RET
DRERR:	MOV	@DISK_STATUS1,BAD_RESET ; CARD FAILED
	RET
DISK_RESET	ENDP

;----------------------------------------
;	DISK STATUS ROUTINE  (AH = 01H) :
;----------------------------------------

RETURN_STATUS	PROC	NEAR
	MOV	AL,@DISK_STATUS1	; OBTAIN PREVIOUS STATUS
	MOV	@DISK_STATUS1,0 	; RESET STATUS
	RET
RETURN_STATUS	ENDP
PAGE
;----------------------------------------
;	DISK READ ROUTINE    (AH = 02H) :
;----------------------------------------

DISK_READ	PROC	NEAR
	MOV	@CMD_BLOCK+6,READ_CMD
	JMP	COMMANDI
DISK_READ	ENDP

;----------------------------------------
;	DISK WRITE ROUTINE   (AH = 03H) :
;----------------------------------------

DISK_WRITE	PROC	NEAR
	MOV	@CMD_BLOCK+6,WRITE_CMD
	JMP	COMMANDO
DISK_WRITE	ENDP

;----------------------------------------
;	DISK VERIFY	     (AH = 04H) :
;----------------------------------------

DISK_VERF	PROC	NEAR
	MOV	@CMD_BLOCK+6,VERIFY_CMD
	CALL	COMMAND
	JNZ	VERF_EXIT		; CONTROLLER STILL BUSY
	CALL	WAIT
	JNZ	VERF_EXIT		; TIME OUT
	CALL	CHECK_STATUS
VERF_EXIT:
	RET
DISK_VERF	ENDP

;----------------------------------------
;	FORMATTING	     (AH = 05H) :
;----------------------------------------

FMT_TRK 	PROC	NEAR		; FORMAT TRACK	(AH = 005H)
	MOV	@CMD_BLOCK+6,FMTTRK_CMD
	PUSH	ES
	PUSH	BX
	CALL	GET_VEC 		; GET DISK PARAMETERS ADDRESS
	MOV	AL,ES:[BX][14]		; GET SECTORS/TRACK
	MOV	@CMD_BLOCK+1,AL 	; SET SECTOR COUNT IN COMMAND
	POP	BX
	POP	ES
	JMP	CMD_OF			; GO EXECUTE THE COMMAND
FMT_TRK 	ENDP


;----------------------------------------
;	READ DASD TYPE	     (AH = 15H) :
;----------------------------------------

READ_DASD_TYPE	LABEL	NEAR
READ_D_T		PROC	FAR	; GET DRIVE PARAMETERS
	PUSH	DS			; SAVE REGISTERS
	PUSH	ES
	PUSH	BX
	ASSUME	DS:DATA
	CALL	DDS			; ESTABLISH ADDRESSING
	MOV	@DISK_STATUS1,0
	MOV	BL,@HF_NUM		; GET NUMBER OF DRIVES
	AND	DL,7FH			; GET DRIVE NUMBER
	CMP	BL,DL
	JBE	RDT_NOT_PRESENT 	; RETURN DRIVE NOT PRESENT
	CALL	GET_VEC 		; GET DISK PARAMETER ADDRESS
	MOV	AL,ES:[BX][2]		; HEADS
	MOV	CL,ES:[BX][14]
	IMUL	CL			; * NUMBER OF SECTORS
	MOV	CX,ES:[BX]		; MAX NUMBER OF CYLINDERS
	DEC	CX			; LEAVE ONE FOR DIAGNOSTICS
	IMUL	CX			; NUMBER OF SECTORS
	MOV	CX,DX			; HIGH ORDER HALF
	MOV	DX,AX			; LOW ORDER HALF
	SUB	AX,AX
	MOV	AH,03H			; INDICATE FIXED DISK
RDT2:	POP	BX			; RESTORE REGISTERS
	POP	ES
	POP	DS
	CLC				; CLEAR CARRY
	RET	2
RDT_NOT_PRESENT:
	SUB	AX,AX			; DRIVE NOT PRESENT RETURN
	MOV	CX,AX			; ZERO BLOCK COUNT
	MOV	DX,AX
	JMP	RDT2
READ_D_T	ENDP
PAGE
;----------------------------------------
;	GET PARAMETERS	     (AH = 08H) :
;----------------------------------------

GET_PARM_N	LABEL	NEAR
GET_PARM	PROC	FAR		; GET DRIVE PARAMETERS
	PUSH	DS			; SAVE REGISTERS
	PUSH	ES
	PUSH	BX
	ASSUME	DS:ABS0
	MOV	AX,ABS0 		; ESTABLISH ADDRESSING
	MOV	DS,AX
	TEST	DL,1			; CHECK FOR DRIVE 1
	JZ	G0
	LES	BX,@HF1_TBL_VEC
	JMP	SHORT G1
G0:	LES	BX,@HF_TBL_VEC
	ASSUME	DS:DATA
G1:
	CALL	DDS			; ESTABLISH SEGMENT
	SUB	DL,80H
	CMP	DL,MAX_FILE		; TEST WITHIN RANGE
	JAE	G4
	MOV	@DISK_STATUS1,0
	MOV	AX,ES:[BX]		; MAX NUMBER OF CYLINDERS
	SUB	AX,2			; ADJUST FOR 0-N
	MOV	CH,AL
	AND	AX,0300H		; HIGH TWO BITS OF CYLINDER
	SHR	AX,1
	SHR	AX,1
	OR	AL,ES:[BX][14]		; SECTORS
	MOV	CL,AL
	MOV	DH,ES:[BX][2]		; HEADS
	DEC	DH			; 0-N RANGE
	MOV	DL,@HF_NUM		; DRIVE COUNT
	SUB	AX,AX
G5:
	POP	BX			; RESTORE REGISTERS
	POP	ES
	POP	DS
	RET	2
G4:
	MOV	@DISK_STATUS1,INIT_FAIL ; OPERATION FAILED
	MOV	AH,INIT_FAIL
	SUB	AL,AL
	SUB	DX,DX
	SUB	CX,CX
	STC				; SET ERROR FLAG
	JMP	G5
GET_PARM	ENDP

;----------------------------------------
;	INITIALIZE DRIVE     (AH = 09H) :
;----------------------------------------
INIT_DRV	PROC	NEAR
	MOV	@CMD_BLOCK+6,SET_PARM_CMD
	CALL	GET_VEC 		; ES:BX -> PARAMETER BLOCK
	MOV	AL,ES:[BX][2]		; GET NUMBER OF HEADS
	DEC	AL			; CONVERT TO 0-INDEX
	MOV	AH,@CMD_BLOCK+5 	; GET SDH REGISTER
	AND	AH,0F0H 		; CHANGE HEAD NUMBER
	OR	AH,AL			;  TO MAX HEAD
	MOV	@CMD_BLOCK+5,AH
	MOV	AL,ES:[BX][14]		; MAX SECTOR NUMBER
	MOV	@CMD_BLOCK+1,AL
	SUB	AX,AX
	MOV	@CMD_BLOCK+3,AL 	; ZERO FLAGS
	CALL	COMMAND 		; TELL CONTROLLER
	JNZ	INIT_EXIT		; CONTROLLER BUSY ERROR
	CALL	NOT_BUSY		; WAIT FOR IT TO BE DONE
	JNZ	INIT_EXIT		; TIME OUT
	CALL	CHECK_STATUS
INIT_EXIT:
	RET
INIT_DRV	ENDP

;----------------------------------------
;	READ LONG	     (AH = 0AH) :
;----------------------------------------

RD_LONG PROC	NEAR
	MOV	@CMD_BLOCK+6,READ_CMD OR ECC_MODE
	JMP	COMMANDI
RD_LONG 	ENDP

;----------------------------------------
;	WRITE LONG	     (AH = 0BH) :
;----------------------------------------

WR_LONG PROC	NEAR
	MOV	@CMD_BLOCK+6,WRITE_CMD OR ECC_MODE
	JMP	COMMANDO
WR_LONG 	ENDP

;----------------------------------------
;	SEEK		     (AH = 0CH) :
;----------------------------------------

DISK_SEEK	PROC	NEAR
	MOV	@CMD_BLOCK+6,SEEK_CMD
	CALL	COMMAND
	JNZ	DS_EXIT 		; CONTROLLER BUSY ERROR
	CALL	WAIT
	JNZ	DS_EXIT 		; TIME OUT ON SEEK
	CALL	CHECK_STATUS
	CMP	@DISK_STATUS1,BAD_SEEK
	JNE	DS_EXIT
	MOV	@DISK_STATUS1,0
DS_EXIT:
	RET

DISK_SEEK	ENDP
PAGE
;----------------------------------------
;	TEST DISK READY      (AH = 10H) :
;----------------------------------------

TST_RDY PROC	NEAR			; WAIT FOR CONTROLLER
	CALL	NOT_BUSY
	JNZ	TR_EX
	MOV	AL,@CMD_BLOCK+5 	; SELECT DRIVE
	MOV	DX,HF_PORT+6
	OUT	DX,AL
	CALL	CHECK_ST		; CHECK STATUS ONLY
	JNZ	TR_EX
	MOV	@DISK_STATUS1,0 	; WIPE OUT DATA CORRECTED ERROR
TR_EX:	RET
TST_RDY ENDP

;----------------------------------------
;	RECALIBRATE	     (AH = 11H) :
;----------------------------------------

HDISK_RECAL	PROC	NEAR
	MOV	@CMD_BLOCK+6,RECAL_CMD
	CALL	COMMAND 		; START THE OPERATION
	JNZ	RECAL_EXIT		; ERROR
	CALL	WAIT			; WAIT FOR COMPLETION
	JZ	RECAL_X 		; TIME OUT ONE OK ?
	CALL	WAIT			; WAIT FOR COMPLETION LONGER
	JNZ	RECAL_EXIT		; TIME OUT TWO TIMES IS ERROR
RECAL_X:
	CALL	CHECK_STATUS
	CMP	@DISK_STATUS1,BAD_SEEK	; SEEK NOT COMPLETE
	JNE	RECAL_EXIT		; IS OK
	MOV	@DISK_STATUS1,0
RECAL_EXIT:
	CMP	@DISK_STATUS1,0
	RET
HDISK_RECAL	ENDP

;----------------------------------------
;      CONTROLLER DIAGNOSTIC (AH = 14H) :
;----------------------------------------

CTLR_DIAGNOSTIC PROC	NEAR
	CLI				; DISABLE INTERRUPTS WHILE CHANGING MASK
	IN	AL,INTB01		; TURN ON SECOND INTERRUPT CHIP
	AND	AL,0BFH
	JMP	$+2
	OUT	INTB01,AL
	IN	AL,INTA01		; LET INTERRUPTS PASS THRU TO
	AND	AL,0FBH 		;  SECOND CHIP
	JMP	$+2
	OUT	INTA01,AL
	STI
	CALL	NOT_BUSY		; WAIT FOR CARD
	JNZ	CD_ERR			; BAD CARD
	MOV	DX,HF_PORT+7
	MOV	AL,DIAG_CMD		; START DIAGNOSE
	OUT	DX,AL
	CALL	NOT_BUSY		; WAIT FOR IT TO COMPLETE
	MOV	AH,TIME_OUT
	JNZ	CD_EXIT 		; TIME OUT ON DIAGNOSTIC
	MOV	DX,HF_PORT+1		; GET ERROR REGISTER
	IN	AL,DX
	MOV	@HF_ERROR,AL		; SAVE IT
	MOV	AH,0
	CMP	AL,1			; CHECK FOR ALL OK
	JE	SHORT CD_EXIT
CD_ERR: MOV	AH,BAD_CNTLR
CD_EXIT:
	MOV	@DISK_STATUS1,AH
	RET
CTLR_DIAGNOSTIC ENDP

;----------------------------------------
; COMMANDI				:
;	REPEATEDLY INPUTS DATA TILL	:
;	NSECTOR RETURNS ZERO		:
;----------------------------------------
COMMANDI:
	CALL	CHECK_DMA		; CHECK 64K BOUNDARY ERROR
	JC	CMD_ABORT
	MOV	DI,BX
	CALL	COMMAND 		; OUTPUT COMMAND
	JNZ	CMD_ABORT
CMD_I1:
	CALL	WAIT			; WAIT FOR DATA REQUEST INTERRUPT
	JNZ	TM_OUT			; TIME OUT
	MOV	CX,256D 		; SECTOR SIZE IN WORDS
	MOV	DX,HF_PORT
	CLI
	CLD
	REP	INSW			; GET THE SECTOR
	STI
	TEST	@CMD_BLOCK+6,ECC_MODE	; CHECK FOR NORMAL INPUT
	JZ	CMD_I3
	CALL	WAIT_DRQ		; WAIT FOR DATA REQUEST
	JC	TM_OUT
	MOV	DX,HF_PORT
	MOV	CX,4			; GET ECC BYTES
CMD_I2: IN	AL,DX
	MOV	ES:BYTE PTR [DI],AL	; GO SLOW FOR BOARD
	INC	DI
	LOOP	CMD_I2
CMD_I3: CALL	CHECK_STATUS
	JNZ	CMD_ABORT		; ERROR RETURNED
	DEC	@CMD_BLOCK+1		; CHECK FOR MORE
	JNZ	SHORT CMD_I1
CMD_ABORT:
TM_OUT: 	RET
PAGE
;----------------------------------------
; COMMANDO				:
;	REPEATEDLY OUTPUTS DATA TILL	:
;	NSECTOR RETURNS ZERO		:
;----------------------------------------
COMMANDO:
	CALL	CHECK_DMA		; CHECK 64K BOUNDARY ERROR
	JC	CMD_ABORT
CMD_OF: MOV	SI,BX
	CALL	COMMAND 		; OUTPUT COMMAND
	JNZ	CMD_ABORT
	CALL	WAIT_DRQ		; WAIT FOR DATA REQUEST
	JC	TM_OUT			; TOO LONG
CMD_O1: PUSH	DS
	PUSH	ES			; MOVE ES TO DS
	POP	DS
	MOV	CX,256D 		; PUT THE DATA OUT TO THE CARD
	MOV	DX,HF_PORT
	CLI
	CLD
	REP	OUTSW
	STI
	POP	DS			; RESTORE DS
	TEST	@CMD_BLOCK+6,ECC_MODE	; CHECK FOR NORMAL OUTPUT
	JZ	CMD_O3
	CALL	WAIT_DRQ		; WAIT FOR DATA REQUEST
	JC	TM_OUT
	MOV	DX,HF_PORT
	MOV	CX,4			; OUTPUT THE ECC BYTES
CMD_O2: MOV	AL,ES:BYTE PTR [SI]
	OUT	DX,AL
	INC	SI
	LOOP	CMD_O2
CMD_O3:
	CALL	WAIT			; WAIT FOR SECTOR COMPLETE INTERRUPT
	JNZ	TM_OUT			; ERROR RETURNED
	CALL	CHECK_STATUS
	JNZ	CMD_ABORT
	TEST	@HF_STATUS,ST_DRQ	; CHECK FOR MORE
	JNZ	SHORT CMD_O1
	MOV	DX,HF_PORT+2		; CHECK RESIDUAL SECTOR COUNT
	IN	AL,DX			;
	TEST	AL,0FFH 		;
	JZ	CMD_O4			; COUNT = 0  OK
	MOV	@DISK_STATUS1,UNDEF_ERR ; OPERATION ABORTED - PARTIAL TRANSFER
CMD_O4:
	RET

;--------------------------------------------------------
; COMMAND						:
;	THIS ROUTINE OUTPUTS THE COMMAND BLOCK		:
; OUTPUT						:
;	BL = STATUS					:
;	BH = ERROR REGISTER				:
;--------------------------------------------------------

COMMAND PROC	NEAR
	PUSH	BX			; WAIT FOR SEEK COMPLETE AND READY
	MOV	CX,DELAY_2		; SET INITIAL DELAY BEFORE TEST
COMMAND1:
	PUSH	CX			; SAVE LOOP COUNT
	CALL	TST_RDY 		; CHECK DRIVE READY
	POP	CX
	JZ	COMMAND2		; DRIVE IS READY
	CMP	@DISK_STATUS1,TIME_OUT	; TST_RDY TIMED OUT--GIVE UP
	JZ	CMD_TIMEOUT
	LOOP	COMMAND1		; KEEP TRYING FOR A WHILE
	JMP	SHORT COMMAND4		; ITS NOT GOING TO GET READY
COMMAND2:
	POP	BX
	PUSH	DI
	MOV	@HF_INT_FLAG,0		; RESET INTERRUPT FLAG
	CLI				; INHIBIT INTERRUPTS WHILE CHANGING MASK
	IN	AL,INTB01		; TURN ON SECOND INTERRUPT CHIP
	AND	AL,0BFH
	JMP	$+2
	OUT	INTB01,AL
	IN	AL,INTA01		; LET INTERRUPTS PASS THRU TO
	AND	AL,0FBH 		;  SECOND CHIP
	JMP	$+2
	OUT	INTA01,AL
	STI
	XOR	DI,DI			; INDEX THE COMMAND TABLE
	MOV	DX,HF_PORT+1		; DISK ADDRESS
	TEST	@CONTROL_BYTE,0C0H	; CHECK FOR RETRY SUPPRESSION
	JZ	COMMAND3
	MOV	AL,@CMD_BLOCK+6 	; YES-GET OPERATION CODE
	AND	AL,0F0H 		; GET RID OF MODIFIERS
	CMP	AL,20H			; 20H-40H IS READ, WRITE, VERIFY
	JB	COMMAND3
	CMP	AL,40H
	JA	COMMAND3
	OR	@CMD_BLOCK+6,NO_RETRIES ; VALID OPERATION FOR RETRY SUPPRESS
COMMAND3:
	MOV	AL,[@CMD_BLOCK+DI]	; GET THE COMMAND STRING BYTE
	OUT	DX,AL			; GIVE IT TO CONTROLLER
	INC	DI			; NEXT BYTE IN COMMAND BLOCK
	INC	DX			; NEXT DISK ADAPTER REGISTER
	CMP	DX,HF_PORT+8		; ALL DONE?
	JNZ	COMMAND3		; NO--GO DO NEXT ONE
	POP	DI
	RET				; ZERO FLAG IS SET
CMD_TIMEOUT:
	MOV	@DISK_STATUS1,BAD_CNTLR
COMMAND4:
	POP	BX
	CMP	@DISK_STATUS1,0 	; SET CONDITION CODE FOR CALLER
	RET
COMMAND ENDP
PAGE
;----------------------------------------
;	WAIT FOR INTERRUPT		:
; ---------------------------------------
WAIT	PROC	NEAR
	STI				; MAKE SURE INTERRUPTS ARE ON
	SUB	CX,CX			; SET INITIAL DELAY BEFORE TEST
	CLC
	MOV	AX,9000H		; DEVICE WAIT INTERRUPT
	INT	15H
	JC	WT2			; DEVICE TIMED OUT
	MOV	BL,DELAY_1		; SET DELAY COUNT

;-----	WAIT LOOP

WT1:	TEST	@HF_INT_FLAG,80H	; TEST FOR INTERRUPT
	LOOPZ	WT1
	JNZ	WT3			; INTERRUPT--LETS GO
	DEC	BL
	JNZ	WT1			; KEEP TRYING FOR A WHILE

WT2:	MOV	@DISK_STATUS1,TIME_OUT	; REPORT TIME OUT ERROR
	JMP	SHORT WT4
WT3:	MOV	@DISK_STATUS1,0
	MOV	@HF_INT_FLAG,0
WT4:	CMP	@DISK_STATUS1,0 	; SET CONDITION CODE FOR CALLER
	RET
WAIT	ENDP

;----------------------------------------
;	WAIT FOR CONTROLLER NOT BUSY	:
;----------------------------------------
NOT_BUSY	PROC	NEAR
	STI				; MAKE SURE INTERRUPTS ARE ON
	PUSH	BX
	SUB	CX,CX			; SET INITIAL DELAY BEFORE TEST
	MOV	DX,HF_PORT+7
	MOV	BL,DELAY_1
NB1:	IN	AL,DX			; CHECK STATUS
	TEST	AL,ST_BUSY
	LOOPNZ	NB1
	JZ	NB2			; NOT BUSY--LETS GO
	DEC	BL
	JNZ	NB1			; KEEP TRYING FOR A WHILE
	MOV	@DISK_STATUS1,TIME_OUT	; REPORT TIME OUT ERROR
	JMP	SHORT NB3
NB2:	MOV	@DISK_STATUS1,0
NB3:	POP	BX
	CMP	@DISK_STATUS1,0 	; SET CONDITION CODE FOR CALLER
	RET
NOT_BUSY	ENDP

;----------------------------------------
;	WAIT FOR DATA REQUEST		:
;----------------------------------------
WAIT_DRQ	PROC	NEAR
	MOV	CX,DELAY_3
	MOV	DX,HF_PORT+7
WQ_1:	IN	AL,DX			; GET STATUS
	TEST	AL,ST_DRQ		; WAIT FOR DRQ
	JNZ	WQ_OK
	LOOP	WQ_1			; KEEP TRYING FOR A SHORT WHILE
	MOV	@DISK_STATUS1,TIME_OUT	; ERROR
	STC
	RET
WQ_OK:	CLC
	RET
WAIT_DRQ	ENDP
;----------------------------------------
;	CHECK FIXED DISK STATUS 	:
;----------------------------------------
CHECK_STATUS	PROC	NEAR
	CALL	CHECK_ST		; CHECK THE STATUS BYTE
	JNZ	CHECK_S1		; AN ERROR WAS FOUND
	TEST	AL,ST_ERROR		; WERE THERE ANY OTHER ERRORS
	JZ	CHECK_S1		; NO ERROR REPORTED
	CALL	CHECK_ER		; ERROR REPORTED
CHECK_S1:
	CMP	@DISK_STATUS1,0 	; SET STATUS FOR CALLER
	RET
CHECK_STATUS	ENDP
;----------------------------------------
;	CHECK FIXED DISK STATUS BYTE	:
;----------------------------------------
CHECK_ST	PROC	NEAR
	MOV	DX,HF_PORT+7		; GET THE STATUS
	IN	AL,DX
	MOV	@HF_STATUS,AL
	MOV	AH,0
	TEST	AL,ST_BUSY		; IF STILL BUSY
	JNZ	CKST_EXIT		;  REPORT OK
	MOV	AH,WRITE_FAULT
	TEST	AL,ST_WRT_FLT		; CHECK FOR WRITE FAULT
	JNZ	CKST_EXIT
	MOV	AH,NOT_RDY
	TEST	AL,ST_READY		; CHECK FOR NOT READY
	JZ	CKST_EXIT
	MOV	AH,BAD_SEEK
	TEST	AL,ST_SEEK_COMPL	; CHECK FOR SEEK NOT COMPLETE
	JZ	CKST_EXIT
	MOV	AH,DATA_CORRECTED
	TEST	AL,ST_CORRCTD		; CHECK FOR CORRECTED ECC
	JNZ	CKST_EXIT
	MOV	AH,0
CKST_EXIT:
	MOV	@DISK_STATUS1,AH	; SET ERROR FLAG
	CMP	AH,DATA_CORRECTED	; KEEP GOING WITH DATA CORRECTED
	JZ	CKST_EX1
	CMP	AH,0
CKST_EX1:
	RET
CHECK_ST	ENDP
PAGE
;----------------------------------------
;	CHECK FIXED DISK ERROR REGISTER :
;----------------------------------------
CHECK_ER	PROC	NEAR
	MOV	DX,HF_PORT+1		; GET THE ERROR REGISTER
	IN	AL,DX
	MOV	@HF_ERROR,AL
	PUSH	BX
	MOV	CX,8			; TEST ALL 8 BITS
CK1:	SHL	AL,1			; MOVE NEXT ERROR BIT TO CARRY
	JC	CK2			; FOUND THE ERROR
	LOOP	CK1			; KEEP TRYING
CK2:	MOV	BX,OFFSET ERR_TBL	; COMPUTE ADDRESS OF
	ADD	BX,CX			; ERROR CODE
	MOV	AH,BYTE PTR CS:[BX]	; GET ERROR CODE
CKEX:	MOV	@DISK_STATUS1,AH	; SAVE ERROR CODE
	POP	BX
	CMP	AH,0
	RET
ERR_TBL DB	NO_ERR
	DB	BAD_ADDR_MARK,BAD_SEEK,BAD_CMD,UNDEF_ERR
	DB	RECORD_NOT_FND,UNDEF_ERR,BAD_ECC,BAD_SECTOR
CHECK_ER	ENDP

;--------------------------------------------------------
; CHECK_DMA						:
;  -CHECK ES:BX AND # SECTORS TO MAKE SURE THAT IT WILL :
;   FIT WITHOUT SEGMENT OVERFLOW.			:
;  -ES:BX HAS BEEN REVISED TO THE FORMAT SSSS:000X	:
;  -OK IF # SECTORS < 80H (7FH IF LONG READ OR WRITE)	:
;  -OK IF # SECTORS = 80H (7FH) AND BX <= 00H (04H)	:
;  -ERROR OTHERWISE					:
;--------------------------------------------------------
CHECK_DMA	PROC	NEAR
	PUSH	AX			; SAVE REGISTERS
	MOV	AX,8000H		; AH = MAX # SECTORS	AL = MAX OFFSET
	TEST	@CMD_BLOCK+6,ECC_MODE
	JZ	CKD1
	MOV	AX,7F04H		; ECC IS 4 MORE BYTES
CKD1:	CMP	AH,@CMD_BLOCK+1 	; NUMBER OF SECTORS
	JA	CKDOK			; IT WILL FIT
	JB	CKDERR			; TOO MANY
	CMP	AL,BL			; CHECK OFFSET ON MAX SECTORS
	JB	CKDERR			; ERROR
CKDOK:	CLC				; CLEAR CARRY
	POP	AX
	RET				; NORMAL RETURN
CKDERR: STC				; INDICATE ERROR
	MOV	@DISK_STATUS1,DMA_BOUNDARY
	POP	AX
	RET
CHECK_DMA	ENDP

;----------------------------------------
;	SET UP ES:BX-> DISK PARMS	:
;----------------------------------------
GET_VEC PROC	NEAR
	SUB	AX,AX			; GET DISK PARAMETER ADDRESS
	MOV	ES,AX
	ASSUME	ES:ABS0
	TEST	DL,1
	JZ	GV_0
	LES	BX,@HF1_TBL_VEC 	; ES:BX -> DRIVE PARAMETERS
	JMP	SHORT GV_EXIT
GV_0:
	LES	BX,@HF_TBL_VEC		; ES:BX -> DRIVE PARAMETERS
GV_EXIT:
	RET
GET_VEC ENDP

;--- HARDWARE INT  76H -- ( IRQ LEVEL  14 ) -----------------------------
;									:
;	FIXED DISK INTERRUPT ROUTINE					:
;									:
;------------------------------------------------------------------------

HD_INT	PROC	NEAR
	PUSH	AX
	PUSH	DS
	CALL	DDS
	MOV	@HF_INT_FLAG,0FFH	; ALL DONE
	MOV	AL,EOI			; NON-SPECIFIC END OF INTERRUPT
	OUT	INTB00,AL		; FOR CONTROLLER #2
	JMP	$+2			; WAIT
	OUT	INTA00,AL		; FOR CONTROLLER #1
	POP	DS
	STI				; RE-ENABLE INTERRUPTS
	MOV	AX,9100H		; DEVICE POST
	INT	15H			;  INTERRUPT
	POP	AX
	IRET				; RETURN FROM INTERRUPT

HD_INT	ENDP

	DB	'11/15/85'              ; RELEASE MARKER
CODE	ENDS
	END
